﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Infrastucture;
using Data.OleDb;
using Data.Serialization;
using Microsoft.Practices.Unity;
using System.Reflection;
using System.Runtime.Serialization;

namespace TimeSplicerModule.Factories
{
    [Obsolete]
    public interface IFactory<DataType, DomainType>
    { 
        DomainType CreateNew();
        DomainType Add(DomainType obj);
        DomainType Save(DomainType obj);
        DomainType Upsert(DomainType obj);
        DomainType Get(Func<DomainType, bool> where);
        List<DomainType> GetList();
        List<DomainType> GetList(Func<DomainType, bool> where);
    }

 
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="DataType"></typeparam>
    /// <typeparam name="DomainType"></typeparam>
    [Obsolete]
    public class FactoryBase<DataType, DomainType> : IFactory<DataType, DomainType>
    {
        private readonly global::Data.IDataService<DataType> _db;
        private readonly IUnityContainer _container;

        // note to self if you have common fields, may want to add 
        // will also have to add unique and compound unique 

        public FactoryBase()
        {
            
        }

        public FactoryBase(IUnityContainer container, global::Data.IDataService<DataType> dataService)
        {
            _db = dataService;
            //_db = new DataService<DataType>();
            _container = container;
            //_db = _container.Resolve<Data.IDataService<DataType>>();
        }

        public virtual DomainType CreateNew()
        {
            return Activator.CreateInstance<DomainType>();
        }

        public virtual DomainType Add(DomainType obj)
        {
            // check priimary key value
            // todo: this one next will need 
            var dataObject = ModelConverter.ToModel<DataType>(obj);

            var keyValue = PropertyHelpers.GetPrimaryKeyValue(dataObject);
            if (keyValue == Guid.Empty)
                keyValue = PropertyHelpers.SetPrimaryKeyValue(dataObject, Guid.NewGuid());

            // check for existing 
            var existing = _db.GetByPrimaryKey(keyValue);

            if (existing == null)
            {
                //var dataModel = ModelConverter.ToModel<DataType>(obj);
                dataObject = _db.Add(dataObject);
            }


            return ModelConverter.ToModel<DomainType>(dataObject);
        }

        public virtual DomainType Save(DomainType obj)
        {
            var dataModel = ModelConverter.ToModel<DataType>(obj);
            dataModel = _db.Save(dataModel);

            return obj;
        }

        public virtual DomainType Upsert(DomainType obj)
        {
            var dataObject = ModelConverter.ToModel<DataType>(obj);
            var keyValue = PropertyHelpers.GetPrimaryKeyValue(dataObject);

            if (keyValue == Guid.Empty)
                return Add(obj);
            else
                return Save(obj);

        }

        //public DomainType Get(Expression<Func<DataType, bool>> where)
        //{
        //    var p = where.Parameters;
        //    var r = where.Parameters[0].Reduce();
        //    var text = where.Body.ToString();

        //    // so either i have to parse text or find another way

            
        //    // so would have to get the type,
        //    // the name 
        //    // then text parse the strings to get the values

        //    throw new NotImplementedException();
        //}

        public virtual DomainType Get(Func<DomainType, bool> where)
        {
            //var text = where.ToString();
            //var info = new SerializationInfo(typeof(DomainType), new FormatterConverter());
            //where.GetObjectData(info, new StreamingContext());

            //var result = where.GetMethodInfo();
            //var meth = where.GetMethodInfo();
            //var iresult = where.BeginInvoke(Activator.CreateInstance<DomainType>(), new AsyncCallback(x => { return; }), new object());
            //var result = where.GetInvocationList();

            return GetList().FirstOrDefault(where);
        }

        public virtual List<DomainType> GetList()
        {
            List<DomainType> models = new List<DomainType>();

            var recs = _db.GetList();

            foreach (var r in recs)
            {
                var m = ModelConverter.ToModel<DomainType>(r);
                models.Add(m);
            }

            return models;
        }
        public virtual List<DomainType> GetList(Func<DomainType, bool> where)
        {
            return GetList().Where(where).ToList();
        }
    }
}
